import type { Mapless } from '..';
import type { IdHubType } from '../core/IdHub';
import IdHub from '../core/IdHub';
import { Manager } from '../core/manager';
import { getOption } from '../core/utils';
import type {
  Route,
  RoutesManagerOptions,
  TrackManagerOptions,
} from '../index.d';

type RoutesIdHubType = IdHubType & {
  sourceId: string;
  layerId: string;
};

class RoutesManager extends Manager<RoutesIdHubType> {
  private routes: Route[] | undefined = undefined;
  private maxPoints: number;

  constructor(mapless: Mapless, options?: TrackManagerOptions) {
    super(mapless, options, 'heatmap');
    this.onInitialized();
    // 设置最大点数，默认为1000
    this.maxPoints = getOption<number>('maxPoints', options, 1000);
    this.routes = [];
  }

  override createIdHub(_idHub?: IdHubType) {
    const newHub = new IdHub({
      layers: {
        layerId: 'dzmap-routes-layer',
      },
      sources: {
        sourceId: 'dzmap-routes-source',
      },
    }) as RoutesIdHubType;
    super.createIdHub(newHub);
  }

  override initLayers() {
    if (!this.mapless) return;
    const sid = this.idHub?.sourceId;
    this.mapless.addEmptySource(sid);
    this.mapless.addLayer({
      id: this.idHub?.layerId,
      type: 'line',
      source: sid,
      paint: {
        'line-color': [
          'case',
          ['==', ['get', 'visible'], false],
          'rgba(0,0,0,0.2)',
          ['coalesce', ['get', 'color'], '#3388ff'],
        ],
        'line-width': ['coalesce', ['get', 'thickness'], 1],
        'line-dasharray': [
          'case',
          ['==', ['get', 'selected'], true],
          [100000000, 0],
          [5, 2],
        ],
      },
    });
  }

  getFeature = (route: Route) => {
    return {
      type: 'Feature' as const,
      geometry: {
        type: 'LineString' as const,
        coordinates: route.route,
      },
      properties: {
        id: route.id,
        visible: route.visible,
        selected: route.selected,
        thickness: route.thickness,
      },
    };
  };

  getFeatures = (routes: Route[]) => {
    return routes?.map((route) => this.getFeature(route));
  };

  drawRoutes(routes: Route[]) {
    this.routes = routes;
    const linesFeatures = this.getFeatures(routes);
    this.mapless?.setData(this.idHub?.sourceId, {
      type: 'FeatureCollection',
      features: linesFeatures,
    });
  }

  updateRoutes(routes: Route[]) {
    routes.forEach((route) => {
      const index = this.routes?.findIndex((item) => item.id === route.id);
      if (this.routes && index !== undefined) {
        if (index === -1) {
          this.routes?.push(route);
        } else {
          this.routes[index].route.push(...route.route);
          this.routes[index].route = this.routes[index].route.slice(
            -this.maxPoints,
          );
        }
      }
    });
    const linesFeatures = this.getFeatures(this.routes || []);
    this.mapless?.setData(this.idHub?.sourceId, {
      type: 'FeatureCollection',
      features: linesFeatures,
    });
  }

  _lastSelected: Route | null = null;

  setSelected(id: string, selected: boolean) {
    if (selected && this._lastSelected) {
      this._lastSelected.selected = false;
      const source = this.mapless?.getSource(
        this.idHub?.sourceId,
      ) as mapboxgl.GeoJSONSource;
      const feature = this.getFeature(this._lastSelected);
      source.updateData(feature);
    }
    const index = this.routes?.findIndex((s) => s.id === id);
    if (this.routes && index !== undefined && index !== -1) {
      this.routes[index].selected = selected;
      // TODO 配合source的dynamic和feature的id实现局部更新
      const find = this.routes[index];
      const source = this.mapless?.getSource(
        this.idHub?.sourceId,
      ) as mapboxgl.GeoJSONSource;
      const feature = this.getFeature(find);
      source.updateData(feature);
      this._lastSelected = find;
    }
  }

  unselectAll() {
    this.routes?.forEach((s) => {
      s.selected = false;
    });
    const features = this.getFeatures(this.routes || []);
    this.mapless?.setData(this.idHub?.sourceId, {
      type: 'FeatureCollection',
      features,
    });
  }

  removeRoutes(ids: string[]) {
    this.routes = this.routes?.filter((s) => !ids.includes(s.id));
    const features = this.getFeatures(this.routes || []);
    this.mapless?.setData(this.idHub?.sourceId, {
      type: 'FeatureCollection',
      features,
    });
  }

  clearRoutes() {
    this.mapless?.setEmptyData(this.idHub?.sourceId);
    this.routes = [];
  }

  override destroy = () => {
    super.destroy();
    this.routes = undefined;
  };
}

export default RoutesManager;

export const attachRoutes = (
  mapless: Mapless | undefined | null,
  name?: string,
  options?: RoutesManagerOptions,
) => mapless?.use(RoutesManager, name, options);
export const getRoutes = (mapless: Mapless | undefined | null, name?: string) =>
  mapless?.get(RoutesManager, name);
export const detachRoutes = (
  mapless: Mapless | undefined | null,
  name?: string,
) => mapless?.unuse(RoutesManager, name);
